package ch.epfl.lara.matcheck.util.statistics;

import ch.epfl.lara.matcheck.ast._

class TreeStatistic extends TraitStatistic {
  
  private var function_calls: Int = _
  private var extractor_calls: Int = _
  
  def this(program: Tree) {
    this()
    run(program)
  }
  
  private def run(program: Tree): Unit = program match {
    case Program(_,_,objects,classes) => 
      (objects ::: classes).foreach(run(_))
    case ObjectDef(_,_,methods) => 
      methods.foreach(run(_))
    case ClassDef(_,_,_,_,_,_,methods) => 
      methods.foreach(run(_))
    case MethodDef(_,_,_,_,body) =>
      inc_function_calls()
      run(body)
    case Match(_,_,cases) =>
      cases.foreach(run(_))
    case CaseDef(_,pattern,guard,body) =>
      run(pattern)
      if(guard.isDefined) run(guard.get)
      run(body)
    case ClassPattern(_,args) =>
      inc_extractor_calls()
      args.foreach(run(_))
    case Call(obj,_,args) =>
      inc_function_calls()
      run(obj)
      args.foreach(run(_))
    case Select(obj,_) =>
      run(obj)
    case If(cond,then,elze) =>
      run(cond); run(then); run(elze);
    case New(_,args) =>
      args.foreach(run(_))
    case IsInstanceOf(e,_) =>
      run(e)
    case BinaryExpr(left,right) =>
      run(left);run(right)
    case !(e) => run(e)
    case _ => ()
  }
  
  private def inc_function_calls(): Unit = function_calls += 1
  private def inc_extractor_calls(): Unit = extractor_calls += 1
  
  private def calls: Int = extractor_calls + function_calls
  private def extractors: Int = extractor_calls
  
  def verbose() {
    if(!Config.STATS) return ()
    Report.verbose("====================================================")
    Report.verbose("==================== Statistics ====================")
    Report.verbose("====================================================\n")
    
    Report.println("number of extractor's method calls: "+extractors)
    Report.println("total number of method calls: "+calls)
  }
}
